package com.shier.shiercodesandbox.template;

import com.shier.shiercodesandbox.model.ExecuteCodeRequest;
import com.shier.shiercodesandbox.model.ExecuteCodeResponse;
import com.shier.shiercodesandbox.model.ExecuteMessage;
import com.shier.shiercodesandbox.utils.ProcessUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;

import static org.apache.commons.lang3.ObjectUtils.max;

/**
 * 使用 Docker 执行 Java 代码沙箱
 *
 * @author Shier
 */
@Component
public class JavaNativeCodeSandbox extends JavaCodeSandboxTemplate {

    @Autowired
    private JavaDockerCodeSandbox javaDockerCodeSandbox;

    @Autowired
    private CppDockerCodeSandbox cppDockerCodeSandbox;  // 注入 CppDockerCodeSandbox
    /**
     * 执行程序
     * @param executeCodeRequest 请求体
     * @return ExecuteCodeResponse 执行结果
     */
    @Override
    public ExecuteCodeResponse executeCode(ExecuteCodeRequest executeCodeRequest) {
        // 获取用户代码及输入
        String code = executeCodeRequest.getCode();
        List<String> inputList = executeCodeRequest.getInputList();
        String language = executeCodeRequest.getLanguage();  // 获取语言类型

        String userCodeDir = "/home/user/code";  // 宿主机目录
        File dir = new File(userCodeDir);

        // 如果目录不存在则创建它
        if (!dir.exists()) {
            dir.mkdirs();
        }
        // 保存代码为文件
        File userCodeFile = new File(dir, "Main.java");
        if ("cpp".equalsIgnoreCase(language)) {
            userCodeFile = new File(dir, "Main.cpp");  // 对于 C++ 保存为 Main.cpp
        }
        System.out.println("保存文件路径: " + userCodeFile.getAbsolutePath());

        try (BufferedWriter writer = new BufferedWriter(new FileWriter(userCodeFile))) {
            writer.write(code);
            System.out.println("文件已成功写入.");
        } catch (IOException e) {
            e.printStackTrace();  // 输出异常信息
        }

        // 编译代码，根据语言类型决定编译方式
        ExecuteMessage compileFileExecuteMessage = null;
        File compiledClassFile = null;
        List<ExecuteMessage> executeMessages = null;

        // 处理执行结果
        ExecuteCodeResponse response = new ExecuteCodeResponse();

        if ("java".equalsIgnoreCase(language)) {
            compileFileExecuteMessage = compileFile(userCodeFile);
            if (compileFileExecuteMessage.getExitValue() == 1) {
                response.setStatus(2);  // 错误
                response.setMessage("编译错误");
                return response;
            }
            // 3. 将编译后的 .class 文件上传到 Docker 容器
            compiledClassFile = new File(dir, "Main.class");
            executeMessages = javaDockerCodeSandbox.runCode(compiledClassFile, inputList);
        } else if ("cpp".equalsIgnoreCase(language)) {
            compileFileExecuteMessage = compileCppFile(userCodeFile);
            if (compileFileExecuteMessage.getExitValue() == 1) {
                response.setStatus(2);  // 错误
                response.setMessage("编译错误");
                return response;
            }
            compiledClassFile = new File(dir, "Main");  // C++ 的可执行文件
            executeMessages = cppDockerCodeSandbox.runCode(compiledClassFile, inputList);
        }

        Long time = 0L;
        Long memory = 0L;
        for (ExecuteMessage message : executeMessages) {
            time = max(time, message.getTime());
            memory = max(memory, message.getMemory());
            if (message.getErrorMessage() != null) {
                response.setStatus(0);  // 错误
                response.setMessage(message.getErrorMessage());
                return response;
            }
        }

        response.setTimeUsage(time);
        response.setMemoryUsage(memory);
//        // 判断输出是否正确
        boolean outputCorrect = compareOutput(executeCodeRequest.getOutputList(), executeMessages);
        if (outputCorrect) {
            response.setStatus(1);  // 正确
            response.setMessage("程序执行成功，输出正确");
        } else {
            response.setStatus(0);  // 错误
            response.setMessage("程序输出错误");
        }
        return response;
    }

    /**
     * 判断输出是否一致
     * @param expectedOutput 期望的输出
     * @param executeMessages 执行后的输出
     * @return 是否一致
     */
    private boolean compareOutput(List<String> expectedOutput, List<ExecuteMessage> executeMessages) {
        // 输出为空的特殊处理
        if (expectedOutput == null || expectedOutput.isEmpty()) {
            return executeMessages.isEmpty();
        }
        if (executeMessages == null || executeMessages.size() != expectedOutput.size()) {
            return false;
        }

        // 比较每行输出，忽略末尾的换行符
        for (int i = 0; i < expectedOutput.size(); i++) {
            // 去除末尾的换行符
            String expected = expectedOutput.get(i).replaceAll("\n$", "");
            String actual = executeMessages.get(i).getMessage().replaceAll("\n$", "");
            if (!expected.equals(actual)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 编译 C++ 文件
     * @param userCodeFile C++ 文件
     * @return 编译结果
     */
    private ExecuteMessage compileCppFile(File userCodeFile) {
        String compiledFilePath = userCodeFile.getParent() + "/Main";
        File oldFile = new File(compiledFilePath);
        if (oldFile.exists()) {
            oldFile.delete();  // 删除旧文件
        }

        String compileCmd = String.format("g++ -std=c++11 -o %s %s", compiledFilePath, userCodeFile.getAbsolutePath());

        try {
            Process compileProcess = Runtime.getRuntime().exec(compileCmd);
            return ProcessUtils.runProcessAndGetMessage(compileProcess, "C++ 编译");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


}
